package com.n9.product.web.action;

import com.n9.base.web.JsonParam;
import com.n9.base.web.WebUtils;
import com.n9.base.web.action.BaseAction;
import com.n9.base.web.vo.RespModel;
import com.n9.common.excel.ExcelUtils;
import com.n9.common.exception.BaseException;
import com.n9.common.page.PageVO;
import com.n9.common.util.DateUtils;
import com.n9.common.util.Utils;
import com.n9.product.entity.*;
import com.n9.product.service.PatentService;
import com.n9.product.service.ProviderService;
import com.n9.product.service.TagService;
import com.n9.product.web.vo.PatentSearchVO;
import com.n9.product.web.vo.PatentVO;
import com.n9.product.web.vo.ReserveRecordVO;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;

/**
 * 专利产品Action
 *
 * @author xqlu
 * @version 2019-01-23
 */
@RestController()
@RequestMapping(value = "${adminPath}/product/patent/")
public class PatentAction extends BaseAction {
    /**
     * 默认优先级
     */
    private static final Integer DEFAULT_PRIORITY = 5;

    @Resource
    private PatentService patentService;
    @Resource
    private TagService tagService;
    @Resource
    private ProviderService providerService;


    /**
     * 模板下载 excel文件列名
     */
    private static final List<String> IMPORT_HEAD_NAMES = Arrays.asList("专利号", "价格");

    /**
     * 分页查询
     *
     * @param page
     * @return
     */
    @RequiresPermissions(value = "product:patent:view")
    @GetMapping()
    public RespModel list(PageVO page, @JsonParam(value = "search") PatentSearchVO search) {
        List<PatentVO> list = patentService.list(page, search);
        return RespModel.normal(page, list);
    }

    /**
     * 查询所有可售
     * @return
     */
    @RequiresPermissions(value = "product:patent:view")
    @GetMapping("/allCanSell")
    public RespModel listAllCanSell() {
        List<PatentVO> vos = patentService.listAllBySaleStatus(SaleStatus.CAN_SELL);
        return RespModel.normal(vos);
    }

    /**
     * 根据ID查询
     *
     * @param id
     * @return
     */
    @RequiresPermissions(value = "product:patent:view")
    @GetMapping("/{id}")
    public RespModel get(@PathVariable String id) {
        PatentVO vo = null;
        if (StringUtils.isNotBlank(id)) {
            vo = patentService.getVo(id);
        }
        return RespModel.normal(vo);
    }

    /**
     * 添加操作
     *
     * @param patent
     * @return
     */
    @RequiresPermissions(value = "product:patent:add")
    @PostMapping()
    public RespModel add(@JsonParam(required = true) PatentVO patent) {
        beanValidator(patent);
        Patent vPatent = voToEntity(patent);
        if (patentService.existsByNo(vPatent.getNo())) {
            return RespModel.defaultError("专利号已被使用");
        }
        PatentVO vo = patentService.save(vPatent);
        return RespModel.normal(vo);
    }

    /**
     * 更新操作
     *
     * @param patent
     * @return
     */
    @RequiresPermissions(value = "product:patent:update")
    @PutMapping()
    public RespModel update(@JsonParam(required = true) PatentVO patent) {
        beanValidator(patent);

        Patent oldPatent = patentService.get(patent.getId());
        if (Objects.isNull(oldPatent)) {
            throw new BaseException("专利不存在,无法修改");
        }

        if (!Objects.equals(oldPatent.getNo(), patent.getNo())) {
            if (patentService.existsByNo(patent.getNo())) {
                throw new BaseException(String.format("专利号:%s,已存在无法修改", patent.getNo()));
            }
        }

        Patent newP = voToEntity(patent);
        BeanUtils.copyProperties(newP, oldPatent, new String[]{"id", "tags", "provider"});
        oldPatent.setTags(newP.getTags());

        return RespModel.normal(patentService.update(oldPatent));
    }


    /**
     * 预留专利
     * @param id
     * @param salesman      销售员
     * @param expireDate    截至日期
     * @param notes         备注
     * @return
     */
    @RequiresPermissions(value = "product:patent:reserve")
    @PutMapping("/{id}/reserve")
    public RespModel reserve(@PathVariable String id,
                             String salesman, String expireDate,
                             @RequestParam(required = false) String notes) {
        Patent patent = patentService.get(id);
        if (Objects.isNull(patent)) {
            return RespModel.defaultError("专利不存在");
        }

        switch (patent.getSaleStatus()) {
            case SELL_OUT:
                return RespModel.defaultError("该专利已售");
            case UNABLE_SELL:
                return RespModel.defaultError("该专利无法销售");
            case RESERVED:
                return RespModel.defaultError("该专利已被预留");
            case CAN_SELL:
                patent.setSaleStatus(SaleStatus.RESERVED);

                ReserveRecord record = new ReserveRecord();
                record.setStatus(ReserveStatus.VALID);
                record.setCreateDate(new Date());
                record.setPatent(patent);
                record.setSalesman(salesman);
                record.setExpireDate(DateUtils.parseDate(expireDate));
                record.setNotes(notes);

                patentService.reserve(patent, record);
                return RespModel.normal();
            default:
                return RespModel.defaultError("该专利未上线销售");
        }
    }

    /**
     * 获取专利的预留记录
     * @param id
     * @return
     */
    @RequiresPermissions(value = "product:patent:view")
    @GetMapping("/{id}/reserve")
    public RespModel getReserveRecord(@PathVariable String id) {
        ReserveRecordVO reserveRecordVO = patentService.getReserveRecordByPatentId(id);
        return RespModel.normal(reserveRecordVO);
    }



    /**
     * 删除操作
     *
     * @param id
     */
    @RequiresPermissions(value = "product:patent:delete")
    @DeleteMapping("/{id}")
    public RespModel delete(@PathVariable String id) {
        if (StringUtils.isBlank(id)) {
            return RespModel.defaultError("记录ID为空，无法修改");
        }
        patentService.delete(id);
        return RespModel.normal();
    }

    /**
     * 批量导入专利,可导入专利信息、价格
     *
     * @param providerId        供应商ID
     * @param file              excel文件
     * @param type PRICE,INFO   导入类型
     */
    @RequiresPermissions(value = "product:patent:import")
    @PostMapping("/import")
    public RespModel batchImport(@RequestParam("file") MultipartFile file,
                                 @RequestParam() PatentImportType type,
                                 @RequestParam(required = false) String providerId) {
        InputStream in;
        try {
             in = file.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
            return RespModel.error(e);
        }

        List<Patent> patents = ExcelUtils.readRows(in, (objects)->{
            if (Objects.isNull(objects)) {
                return null;
            }
            int index = 0;

            String no = Utils.safeToString(objects[index++], null);
            if (StringUtils.isBlank(no)) {
                return null;
            }

            if (Objects.equals(PatentImportType.PRICE, type)) {
                Patent patent = new Patent();
                patent.setNo(no);
                String price = Utils.safeToString(objects[index++], null);
                if (StringUtils.isNotBlank(price)) {
                    patent.setPrice(new BigDecimal(price));
                }
                return patent;
            } else if (Objects.equals(PatentImportType.INFO, type)) {
                Patent patent = new Patent();
                patent.setNo(no);
                patent.setType(getTypeFromNo(no));

                String name = Utils.safeToString(objects[index++], null);
                String status = Utils.safeToString(objects[index++], null);
                String expireDate = Utils.safeToString(objects[index++], null);

                patent.setName(name);
                patent.setStatus(status);
                if (StringUtils.isNotBlank(expireDate)) {
                    patent.setExpireDate(DateUtils.parseDate(expireDate));
                }
                return patent;
            }
            return null;
        });

        if (Objects.equals(PatentImportType.INFO, type)) {
            patentService.saveOrUpdateInfo(patents);
        } else if (Objects.equals(PatentImportType.PRICE, type)) {
            Provider provider = providerService.getById(providerId);
            if (Objects.isNull(provider)) {
                return RespModel.defaultError("导入失败,供应商不存在");
            }
            patents.forEach(pt -> {
                pt.setProvider(provider);
                pt.setPriority(provider.getPriority());
                pt.setType(getTypeFromNo(pt.getNo()));
                pt.setSaleStatus(SaleStatus.CAN_SELL);
            });
            patentService.saveOrUpdatePrice(patents);
        }
        return RespModel.normal("成功导入数量:" + patents.size());
    }

    /**
     * 下载模板
     */
    @RequiresPermissions(value = "product:patent:import")
    @GetMapping("/download-template")
    public void downloadTemplate(HttpServletResponse response) {
        WebUtils.writeToExcel(IMPORT_HEAD_NAMES, null, null, "专利导入模板-价格.xlsx", response);
    }

    /**
     * 导出没信息的专利
     * @return
     */
    @RequiresPermissions(value = "product:patent:import")
    @GetMapping("/downloadNoInfo")
    public RespModel download(HttpServletResponse response) {
        List<String> list = patentService.listAllNoInfoNos();

        final String fileName = "需补充信息的专利号" + DateUtils.formatDate(new Date()) + ".txt";
        WebUtils.setFileName(response, fileName);

        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
            for (String no: list) {
                out.println(no);
            }
            out.flush();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
            return RespModel.defaultError(e.getMessage());
        } finally {
            if (Objects.nonNull(out)) {
                try {
                    out.close();
                } catch (IOException e) {
                    //ignore
                }
            }
        }
        return RespModel.normal();
    }

    /**
     * 设置标签
     *
     * @param id
     * @param tagNames
     * @return
     */
    @RequiresPermissions(value = "product:patent:update")
    @PutMapping("/{id}/setTag")
    public RespModel setTag(@PathVariable String id, String[] tagNames) {
        Patent patent = patentService.get(id);
        if (Objects.isNull(patent)) {
            return RespModel.defaultError("专利不存在");
        }

        if (Objects.isNull(tagNames)) {
            tagNames = new String[0];
        }
        setTags(patent, tagNames);

        return RespModel.normal(patentService.update(patent));
    }

    /**
     * 产品下架：下架供应商所有专利，预留、已售的除外
     *
     * @param providerId
     * @return
     */
    @RequiresPermissions(value = "product:patent:update")
    @PutMapping("/down")
    public RespModel down(String providerId) {
        Provider provider = providerService.getById(providerId);
        if (Objects.isNull(provider)) {
            return RespModel.defaultError("供应商不存在");
        }

        patentService.setUnsellByProvider(provider);
        return RespModel.normal();
    }

    /**
     * vo转entity
     *
     * @param vo
     * @return
     */
    private Patent voToEntity(PatentVO vo) {
        if (Objects.isNull(vo)) {
            return null;
        }
        Patent patent = new Patent();
        BeanUtils.copyProperties(vo, patent, new String[]{"expireDate", "price"});
        setTags(patent, vo.getTagNames());
        patent.setExpireDate(DateUtils.parseDate(vo.getExpireDate()));
        patent.setPrice(new BigDecimal(vo.getPrice()));

        Integer priority = patent.getPriority() == null ? DEFAULT_PRIORITY : patent.getPriority();
        patent.setPriority(priority);

        PatentType patentType = getTypeFromNo(vo.getNo());
        patent.setType(patentType);

        if (StringUtils.isNotBlank(vo.getProviderId())) {
            Provider provider = providerService.getById(vo.getProviderId());
            if (Objects.nonNull(provider)) {
                patent.setProvider(provider);
            }
        }

        return patent;
    }

    /**
     * 设置标签
     * @param patent
     * @param tagNames
     */
    private void setTags(Patent patent, String[] tagNames) {
        if (Objects.nonNull(tagNames)) {
            List<Tag> tags = new ArrayList<>(0);
            for (String tagName : tagNames) {
                tagName = tagName.trim();
                Tag tag = tagService.getTagByName(tagName);

                if (Objects.isNull(tag)) {
                    tag = new Tag();
                    tag.setName(tagName);
                }

                boolean exists = false;
                for (Tag t : tags) {
                    if (t.getName().equals(tag.getName())) {
                        exists = true;
                        break;
                    }
                }
                if (!exists) {
                    tags.add(tag);
                }
            }
            patent.setTags(tags);
            patent.setTagCount(tags.size());
        }
    }

    /**
     * 根据专利号获取专利类型
     * @param no
     * @return
     */
    private PatentType getTypeFromNo(String no) {
        if (StringUtils.isBlank(no) || no.length() < 5) {
            return null;
        }
        switch (no.charAt(4)) {
            case '1':
                return PatentType.INVENTION;
            case '2':
                return PatentType.DESIGN;
            case '3':
                return PatentType.UTILITY_MODEL;
            case '8':
                return PatentType.PCT_INVENTION;
            case '9':
                return PatentType.PCT_UTILITY_MODEL;
            default:
                return null;
        }
    }
}
